package org.paradigmshift.timelapse.ui

import java.awt.Insets
import java.util.Date
import scala.swing.event.ButtonClicked
import scala.swing.BorderPanel
import scala.swing.BoxPanel
import scala.swing.GridBagPanel
import scala.swing.Label
import scala.swing.Orientation
import scala.swing.ScrollPane
import scala.swing.Swing
import scala.swing.TextArea
import org.paradigmshift.timelapse.actor.messages.Exit
import org.paradigmshift.timelapse.daos.WorklogDao
import org.paradigmshift.timelapse.domain.Issue
import org.paradigmshift.timelapse.domain.User
import org.paradigmshift.timelapse.domain.Worklog
import org.paradigmshift.timelapse.exceptions.AuthorizationException
import org.paradigmshift.timelapse.exceptions.InvalidInputException
import org.paradigmshift.timelapse.exceptions.PermissionDeniedException
import org.paradigmshift.timelapse.exceptions.TimeLapseException
import org.paradigmshift.timelapse.stopwatch.Add
import org.paradigmshift.timelapse.stopwatch.GetStartDate
import org.paradigmshift.timelapse.stopwatch.Pause
import org.paradigmshift.timelapse.stopwatch.Paused
import org.paradigmshift.timelapse.stopwatch.Reset
import org.paradigmshift.timelapse.stopwatch.Start
import org.paradigmshift.timelapse.stopwatch.Started
import org.paradigmshift.timelapse.stopwatch.Stopwatch
import org.paradigmshift.timelapse.stopwatch.Time
import org.paradigmshift.timelapse.TimeLapsePreferences.prefs

import javax.swing.JOptionPane
import org.paradigmshift.timelapse.exceptions.AuthorizationException
import org.paradigmshift.timelapse.rest.JsonRestConnection
import scala.swing.event.Key
import scala.swing.event.KeyPressed

class IssuePanel( issue:Issue ) extends BorderPanel {
  private val MAC_SEGMENTED_TEXTURED_BUTTON_STYLE = "segmentedTextured"
  
  private val stopwatch = new Stopwatch
  
  // Controls and Outputs
  private val stopwatchDisplay = new StopwatchDisplay
  private val startStopButton:TimeLapseButton = new TimeLapseButton {
    focusable = false
    text = "Start"
    var toggleStartStop = () => stopwatch ! Start
    reactions += { case ButtonClicked( `startStopButton` ) => this.toggleStartStop() }
    
    start()
    
    def act() {
      loop {
        react {
          case Started =>
            text = "Pause"
            toggleStartStop = () => stopwatch ! Pause
          case Paused =>
            text = "Start"
            toggleStartStop = () => stopwatch ! Start
          case Exit => exit
          case _ =>
        }
      }
    }
  }
  private val logWorkButton:TimeLapseButton = new TimeLapseButton {
    private var seconds:Int = 0
    
    text = "Log"
    enabled = false
    focusable = false
    reactions += {
      case ButtonClicked( `logWorkButton` ) => {
        if ( seconds > 0 ) {
          if ( !JsonRestConnection.isAuthSet ) TimeLapseUI.loginDialog.open()
          
          val result = Option( JOptionPane.showInputDialog( this.peer, "Description:", "Log Work", JOptionPane.INFORMATION_MESSAGE ) )
          
          result.foreach( description => {
            val startDate = (stopwatch !? GetStartDate) match {
              case Some( date:Date ) => date
              case _ => throw new TimeLapseException( "No start date" )
            }
            
            for { key <- issue.key } yield {
              val worklog = new Worklog( None, None, description, startDate, if (seconds < 60) 60 else seconds )
              
              try {
                var success = false
                for { tries <- 0 to 3; if ( !success ) } yield {
                  try {
                    WorklogDao.create( key, worklog )
                    success = true
                    stopwatch ! Reset
                  }
                  catch {
                    case e:InvalidInputException =>
                      if ( tries < 3 )
                        TimeLapseUI.loginDialog.open()
                      else
                       JOptionPane.showMessageDialog( this.peer, "Invalid username or password!", "Error", JOptionPane.ERROR_MESSAGE )
                  }
                }
              }
              catch {
                case e:PermissionDeniedException =>
                  JOptionPane.showMessageDialog( this.peer, "You do not have permission.  Check the JIRA website for a Captcha.", "Error", JOptionPane.ERROR_MESSAGE )
                case e:AuthorizationException =>
                  JOptionPane.showMessageDialog( this.peer, "You are not authorized.", "Error", JOptionPane.ERROR_MESSAGE )
                case e:Exception =>
                  JOptionPane.showMessageDialog( this.peer, e.getClass() + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE )
              }
            }
          })
        }
      }
    }
    
    start()
    
    def act() {
      loop {
        react {
          case Paused => enabled = (seconds > 0)
          case Started => enabled = false
          case Time( 0 ) => enabled = false
          case Time( t ) => seconds = t
          case Exit => exit
          case _ =>
        }
      }
    }
  }
  private val resetButton:TimeLapseButton = new TimeLapseButton {
    private var seconds:Long = 0
    
    text = "Reset"
    enabled = false
    focusable = false
    reactions += {
      case ButtonClicked( `resetButton` ) => 
        stopwatch ! Reset
        enabled = false
    }
    
    start()
    
    def act() {
      loop {
        react {
          case Paused => enabled = ( seconds > 0 )
          case Started => enabled = false
          case Time( 0 ) => enabled = false
          case Time( t ) => seconds = t
          case Exit => exit
          case _ =>
        }
      }
    }
  }
  
  // Connect the elements to the stopwatch
  stopwatch ! Add( stopwatchDisplay :: startStopButton :: logWorkButton :: resetButton :: Nil )
  
  // Layout
  private val buttonBox = new BoxPanel( Orientation.Horizontal ) {
    contents += startStopButton
    contents += logWorkButton
    contents += resetButton
  }
  
  private val controlPanel = new BoxPanel( Orientation.Horizontal ) {
    border = Swing.BeveledBorder( Swing.Raised )
    contents += buttonBox
    contents += stopwatchDisplay
  }
  
  private val centerPanel = new GridBagPanel() {
    border = Swing.EmptyBorder( 10 )
    
    private val c = new Constraints
    c.anchor = GridBagPanel.Anchor.NorthWest
    
    c.fill = GridBagPanel.Fill.None
    c.grid = ( 0, 0 )
    c.insets = new Insets( 5, 0, 0, 0 )
    layout( new Label( "Issue:" ) ) = c
    c.gridy = 1
    layout( new Label( "Description:" ) ) = c
    c.gridy = 2
    layout( new Label( "Priority:" ) ) = c
    c.gridy = 3
    layout( new Label( "Assignee:" ) ) = c
    c.gridy = 4
    layout( new Label( "Reporter:" ) ) = c
    c.gridy = 5
    layout( new Label( "Summary:" ) ) = c
    
    private val unknownUser = new User( "", "" )
    private val assignee = issue.assignee.getOrElse( unknownUser )
    private val reporter = issue.reporter.getOrElse( unknownUser )
  
    c.grid = ( 1, 0 )
    c.weightx = 1.0
    c.insets = new Insets( 5, 10, 0, 0 )
    c.fill = GridBagPanel.Fill.Horizontal
    layout( new TextArea( issue.key.getOrElse( "Unknown" ) ) { lineWrap = true; editable = false; opaque = false } ) = c
    c.gridy = 1
    layout( new TextArea( issue.description ) { lineWrap = true; editable = false; opaque = false } ) = c
    c.gridy = 2
    layout( new TextArea( issue.priority ) { lineWrap = true; editable = false; opaque = false } ) = c
    c.gridy = 3
    layout( new TextArea( assignee.username ) { lineWrap = true; editable = false; opaque = false; tooltip = assignee.displayName } ) = c
    c.gridy = 4
    layout( new TextArea( reporter.username ) { lineWrap = true; editable = false; opaque = false; tooltip = reporter.displayName } ) = c
    
    c.gridy = 5
    c.gridwidth = 2
    c.weighty = 1.0
    c.fill = GridBagPanel.Fill.Both
    layout( new ScrollPane( new TextArea( issue.summary ) { columns = 25; editable = false } ) ) = c
  }
  
  layout( controlPanel ) = BorderPanel.Position.North
  layout( centerPanel ) = BorderPanel.Position.Center
  
  listenTo( keys, startStopButton.keys, logWorkButton.keys, resetButton.keys )
//  reactions += {
//    case KeyPressed( _, Key.S, TimeLapseUI.systemMask, _ ) => startStopButton.doClick
//    case KeyPressed( _, Key.L, TimeLapseUI.systemMask, _ ) => logWorkButton.doClick
//    case KeyPressed( _, Key.R, TimeLapseUI.systemMask, _ ) => resetButton.doClick
//    case KeyPressed( _, key, mod, _ ) => {
//      if ( TimeLapseUI.isMac && mod == TimeLapseUI.systemMask && key == Key.W ) close
//      else if ( key == Key.Escape ) close
//    }
//  }
//  requestFocus
  
  // LAF
  if ( OSValidator.isMac ) {
    startStopButton.peer.putClientProperty( "JButton.buttonType", MAC_SEGMENTED_TEXTURED_BUTTON_STYLE )
    startStopButton.peer.putClientProperty( "JButton.segmentPosition", "first" )
    logWorkButton.peer.putClientProperty( "JButton.buttonType", MAC_SEGMENTED_TEXTURED_BUTTON_STYLE )
    logWorkButton.peer.putClientProperty( "JButton.segmentPosition", "middle" )
    resetButton.peer.putClientProperty( "JButton.buttonType", MAC_SEGMENTED_TEXTURED_BUTTON_STYLE )
    resetButton.peer.putClientProperty( "JButton.segmentPosition", "last" )
  }
  
  def close() {
    stopwatchDisplay ! Exit
    startStopButton ! Exit
    logWorkButton ! Exit
    resetButton ! Exit
    stopwatch ! Exit
  }
}